IOMMU: keep disabled until iommu_setup() is called
authorJan Beulich <jbeulich@suse.com>
Fri, 2 Nov 2012 16:15:30 +0000 (17:15 +0100)
committerJan Beulich <jbeulich@suse.com>
Fri, 2 Nov 2012 16:15:30 +0000 (17:15 +0100)
The iommu is enabled by default when xen is booting and later disabled
in iommu_setup() when no iommu is present.

But under some circumstances iommu code can be called before
iommu_setup() is processed. If there is no iommu available xen crashes.

This can happen for example when panic(...) is called as introduced
with the patch "x86-64: detect processors subject to AMD erratum #121
and refuse to boot" since xen 4.1.3, resulting in
find_iommu_for_device() to be called in the context of
disable_IO_APIC() / __stop_this_cpu().

This patch fixes this by keeping the iommu disabled until iommu_setup()
is entered.

Originally-by: Ronny Hegewald <ronny.hegewald@online.de>
In order for iommu_enable to be off initially, iommu_supports_eim()
must not depend on it anymore, nor must acpi_parse_dmar(). The former
in turn requires that iommu_intremap gets uncoupled from iommu_enabled
(in particular, failure during IOMMU setup should no longer result in
iommu_intremap getting cleared by generic code; IOMMU specific code
can still do so provided in can live with the consequences).

This could have the nice side effect of allowing to use "iommu=off"
even when x2APIC was pre-enabled by the BIOS (in which case interrupt
remapping is a requirement, but DMA translation [obviously] isn't), but
that doesn't currently work (and hence x2apic_bsp_setup() forces the
IOMMU on rather than just interrupt remapping).

For consistency with VT-d, make the AMD IOMMU code also skip all ACPI
table parsing when neither iommu_enable nor iommu_intremap are set.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
Acked-by: "Huang2, Wei" <Wei.Huang2@amd.com>
xen/arch/x86/apic.c
xen/drivers/passthrough/amd/pci_amd_iommu.c
xen/drivers/passthrough/iommu.c
xen/drivers/passthrough/vtd/dmar.c
xen/drivers/passthrough/vtd/intremap.c
xen/drivers/passthrough/vtd/iommu.c
xen/include/xen/iommu.h

index ccd6f47914f6bb9d870ea9d2c9e9c8f695c174e4..aa75e52576c863df7c6c910e5b25b4fdc321b39b 100644 (file)
@@ -975,6 +975,8 @@ void __init x2apic_bsp_setup(void)
         goto restore_out;
     }
 
+    force_iommu = 1;
+
     genapic = apic_x2apic_probe();
     printk("Switched to APIC driver %s.\n", genapic->name);
 
index b633f1ca775235eb601493ee622d10871f6ea7c6..922dd2205dcfad45688ab900559f5b121bb31ba9 100644 (file)
@@ -164,9 +164,13 @@ int __init amd_iov_detect(void)
 {
     INIT_LIST_HEAD(&amd_iommu_head);
 
+    if ( !iommu_enable && !iommu_intremap )
+        return 0;
+
     if ( (amd_iommu_detect_acpi() !=0) || (iommu_found() == 0) )
     {
         printk("AMD-Vi: IOMMU not found!\n");
+        iommu_intremap = 0;
         return -ENODEV;
     }
 
index 3f14a376618f321586e0866cce62779889081639..efea1223e7912a0a6e4edffa95b6a8243d59bc4c 100644 (file)
@@ -41,7 +41,8 @@ static void iommu_dump_p2m_table(unsigned char key);
  *   no-intremap                Disable VT-d Interrupt Remapping
  */
 custom_param("iommu", parse_iommu_param);
-bool_t __read_mostly iommu_enabled = 1;
+bool_t __initdata iommu_enable = 1;
+bool_t __read_mostly iommu_enabled;
 bool_t __read_mostly force_iommu;
 bool_t __initdata iommu_dom0_strict;
 bool_t __read_mostly iommu_verbose;
@@ -77,7 +78,7 @@ static void __init parse_iommu_param(char *s)
             *ss = '\0';
 
         if ( !parse_bool(s) )
-            iommu_enabled = 0;
+            iommu_enable = 0;
         else if ( !strcmp(s, "force") || !strcmp(s, "required") )
             force_iommu = val;
         else if ( !strcmp(s, "workaround_bios_bug") )
@@ -395,7 +396,7 @@ int __init iommu_setup(void)
     if ( iommu_dom0_strict )
         iommu_passthrough = 0;
 
-    if ( iommu_enabled )
+    if ( iommu_enable )
     {
         rc = iommu_hardware_setup();
         iommu_enabled = (rc == 0);
@@ -409,8 +410,6 @@ int __init iommu_setup(void)
     if ( !iommu_enabled )
     {
         iommu_snoop = 0;
-        iommu_qinval = 0;
-        iommu_intremap = 0;
         iommu_passthrough = 0;
         iommu_dom0_strict = 0;
     }
index a6a11b033ad1087109d3dc87c4efca7435abb478..eddb9e2dbb2f38319fff157bdb14068a729a0516 100644 (file)
@@ -744,7 +744,7 @@ static int __init acpi_parse_dmar(struct acpi_table_header *table)
     dmar = (struct acpi_table_dmar *)table;
     dmar_flags = dmar->flags;
 
-    if ( !iommu_enabled )
+    if ( !iommu_enable && !iommu_intremap )
     {
         ret = -EINVAL;
         goto out;
index c53ab66da6aecba4f4d6cc5eb66fddb6b7b64d92..1d3e0d2db746fc2cb63693af3cd39b75170a283b 100644 (file)
@@ -149,8 +149,7 @@ int iommu_supports_eim(void)
     struct acpi_drhd_unit *drhd;
     int apic;
 
-    if ( !iommu_enabled || !iommu_qinval || !iommu_intremap ||
-         list_empty(&acpi_drhd_units) )
+    if ( !iommu_qinval || !iommu_intremap || list_empty(&acpi_drhd_units) )
         return 0;
 
     /* We MUST have a DRHD unit for each IOAPIC. */
index 287fd4616d5c1613cc394ec5e2b39a772e77c159..178a40c97f9df753218db140803e125de2ebae32 100644 (file)
@@ -2086,7 +2086,10 @@ int __init intel_vtd_setup(void)
     int ret;
 
     if ( list_empty(&acpi_drhd_units) )
-        return -ENODEV;
+    {
+        ret = -ENODEV;
+        goto error;
+    }
 
     platform_quirks_init();
 
index 88420a5fcee89d9856ab89b59be737f9179b87ef..3026e54606298fdc2c3f094f8f801904a2821498 100644 (file)
@@ -26,7 +26,7 @@
 #include <public/hvm/ioreq.h>
 #include <public/domctl.h>
 
-extern bool_t iommu_enabled;
+extern bool_t iommu_enable, iommu_enabled;
 extern bool_t force_iommu, iommu_verbose;
 extern bool_t iommu_workaround_bios_bug, iommu_passthrough;
 extern bool_t iommu_snoop, iommu_qinval, iommu_intremap;